home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / alpha / dipc / dipc-0.000 / dipc-0 / dipc-0.15 / dipcd / referee.c < prev    next >
C/C++ Source or Header  |  1996-07-16  |  23KB  |  878 lines

  1. /*
  2.  * referee.c
  3.  *
  4.  * part of dipcd source code
  5.  *
  6.  * Copyright (C) Kamran Karimi
  7.  */
  8.  
  9. #include "dipcd.h"
  10. #include "funcs.h"
  11.  
  12. #include "back_door.h"
  13.  
  14. char back_ux_name[80];
  15.  
  16. /* for the status field. All received queries first have the REF_WAITING 
  17.    state. After an answer is sent to them, they are in REF_ANSWERED state.
  18.    When the successfully create the IPC structure, they will be promoted to
  19.    REF_NORMAL state */
  20. #define REF_WAITING  0
  21. #define REF_ANSWERED 1
  22. #define REF_NORMAL   2
  23.  
  24. extern struct sockaddr_in REFEREE_ADDRESS;
  25.  
  26. extern int verbose;
  27. extern int global_timeout;
  28. extern int referee_timeout;
  29.  
  30. static char ipc_type[3][4] = 
  31. {
  32.  "SHM",
  33.  "MSG",
  34.  "SEM"
  35. };
  36.  
  37. struct dipc_list 
  38. {
  39.  key_t key;
  40.  int size;
  41.  int distrib;
  42.  int status;
  43.  int pid;
  44.  int mode;
  45.  time_t answer_time;
  46.  struct sockaddr_in address;
  47.  struct dipc_info info;
  48.  struct dipc_list *next,*prev;
  49. };
  50. /* There are six queue in the referee. They are divided into two main types. 
  51.    The three queues in each type are one for shared memories, one for message
  52.    queues, and one for semaphore sets. The 'wanted' linked list is for new 
  53.    queries to search for a key. If the corresponding structures are 
  54.    successfully created in the local, the corresponding element will be 
  55.    brought to the 'gotten' linked list */
  56. struct dipc_list gotten_first[3];
  57. struct dipc_list *gotten_last[3];
  58.  
  59. struct dipc_list wanted_first[3];
  60. struct dipc_list *wanted_last[3];
  61.  
  62.  
  63. static void add_to_list(struct dipc_list **last, struct dipc_list *dl)
  64. {
  65.  dl->next = NULL;
  66.  dl->prev = *last;
  67.  (*last)->next = dl;
  68.  *last = dl;
  69. }
  70.  
  71. static struct dipc_list *find_in_list(struct dipc_list *first, int key)
  72. {
  73.  struct dipc_list *dl2 = first->next;
  74.  
  75.  while(dl2)
  76.  {
  77.   if(dl2->info.key == key)
  78.    break;
  79.   dl2 = dl2->next;
  80.  }
  81.  return dl2;
  82. }
  83.  
  84. static void remove_from_list(struct dipc_list **last, struct dipc_list *dl)
  85. {
  86.  if(dl == *last)
  87.   (*last) = (*last)->prev; 
  88.  (dl->prev)->next = dl->next;
  89.  if(dl->next)
  90.   (dl->next)->prev = dl->prev;
  91. }
  92.  
  93. static struct dipc_list *get_next_key(struct dipc_list *dl)
  94. {
  95.  struct dipc_list *dl2 = dl->next;
  96.  
  97.  while(dl2)
  98.  {
  99.   if(dl2->info.key == dl->info.key) 
  100.    break;
  101.   dl2 = dl2->next;
  102.  }
  103.  return dl2;
  104.  
  105. /* searches to see if it can find a registered key that is the same as the 
  106.    one in the query. It sends this information to the computer that asked
  107.    for it */ 
  108. static BOOLEAN respond_to(struct dipc_list *query)
  109. {
  110.  struct message response;
  111.  struct dipc_list *dl;
  112.  int type;
  113.  
  114.  response.info = query->info;  
  115.  response.address = REFEREE_ADDRESS;
  116.  response.pid = query->pid;
  117.  response.request = RES_REFEREE;
  118.  
  119.  type = query->info.type;
  120.  dl = find_in_list(&gotten_first[type], query->key);
  121.  if(dl)
  122.  {
  123.   if(verbose)
  124.   {
  125.    sprintf(mstr,"Found Existing Key %d of type %s From %s",
  126.            dl->key,ipc_type[type], inet_ntoa(dl->address.sin_addr));
  127.    mess(mstr, INFO);
  128.   }
  129.   response.info.arg3 = dl->size;
  130.   response.info.arg4 = dl->address.sin_addr.s_addr;
  131.   if(dl->distrib)
  132.   {
  133.    if(verbose)
  134.    {
  135.     sprintf(mstr,"found DIPC");
  136.     mess(mstr, INFO);
  137.    } 
  138.    response.info.arg2 = FOUND_DIPC;
  139.   }
  140.   else
  141.   {
  142.    if(verbose)
  143.    {
  144.     sprintf(mstr,"found IPC");
  145.     mess(mstr, INFO);
  146.    }
  147.    response.info.arg2 = FOUND_IPC; 
  148.   }  
  149.   /* sprintf(mstr,"owner address is %s",inet_ntoa(dl->address.sin_addr));
  150.      mess(mstr, INFO); */
  151.  }
  152.  else
  153.  { /* no gotten found */
  154.   if(verbose)
  155.   {
  156.    sprintf(mstr,"key not found");
  157.    mess(mstr, INFO);
  158.   }
  159.   response.info.arg3 = 0;
  160.   response.info.arg4 = query->address.sin_addr.s_addr; /* its own address */
  161.   response.info.arg2 = NOT_FOUND;
  162.  } 
  163.  if(send_in_message(&response, query->address) == FAIL)
  164.  {
  165.   sprintf(mstr,"ERROR: Can't Return Result Of Search");
  166.   mess(mstr, INFO);
  167.   remove_from_list(&wanted_last[type], query);
  168.   free(query);
  169.   return FAIL;
  170.  }
  171.  query->status = REF_ANSWERED;
  172.  query->answer_time = time(NULL); 
  173.  return SUCCESS;
  174. }
  175.  
  176.  
  177. /* Places the query in the 'wanted' linked list and then conducts a search 
  178.    in the referee linked lists. If the query can be answered, it will
  179.    call respond_to, otherwise it has to wait for the results of earlier 
  180.    queries */
  181. static BOOLEAN referee_dipc_search(struct message *message)
  182. {
  183.  struct dipc_list *dl, *dl2;
  184.  int type = message->info.type;
  185.  
  186.  if(verbose)
  187.  {
  188.   sprintf(mstr,"Handling Search For Key %d of type %s",
  189.             message->info.key, ipc_type[type]);
  190.   mess(mstr, INFO);
  191.  }
  192.  /* we should put the request in a linked list, waiting for a commit answer. */  
  193.  dl2 = (struct dipc_list *)malloc(sizeof(struct dipc_list));
  194.  if(dl2 == NULL)
  195.  {
  196.   sprintf(mstr,"ERROR: No Mem");
  197.   mess(mstr, INFO);
  198.   return FAIL;
  199.  }
  200.  dl2->key = message->info.key;
  201.  dl2->pid = message->pid;
  202.  dl2->info = message->info;
  203.  dl2->size = message->info.arg3;
  204.  dl2->distrib = message->info.arg2;
  205.  dl2->status = REF_WAITING;
  206.  if(verbose)
  207.  {
  208.   if(dl2->distrib)
  209.   {
  210.    sprintf(mstr,"new request is DIPC");
  211.    mess(mstr, INFO);
  212.   }  
  213.   else
  214.   {
  215.    sprintf(mstr,"new request is IPC");
  216.    mess(mstr, INFO);
  217.   }  
  218.  }  
  219.  dl2->address = message->address;
  220.  
  221.  /* see if another one is already waiting. do this before putting the new 
  222.     query in the list. */
  223.  dl = find_in_list(&wanted_first[type], message->info.key);
  224.  /* now put the new query in the list */
  225.  add_to_list(&wanted_last[type], dl2);
  226.  if(dl)
  227.  { /* found another query, the new one should wait */
  228.   if(verbose)
  229.   {
  230.    sprintf(mstr,"Key %d Must Wait",message->info.key);    
  231.    mess(mstr, INFO);
  232.   }
  233.  }
  234.  else
  235.  {
  236.   /* this is the only request. answer it now */
  237.   if(FAIL == respond_to(dl2))
  238.    return FAIL;
  239.  }
  240.  return SUCCESS; 
  241. }
  242.  
  243.  
  244. /* handles the commit messages. If the structure is created in the local
  245.    machine, the request will be put in the 'gotten' linked list. otherwise
  246.    it is thrown away. In any case it is checked to see if other quesries
  247.    have been waiting for this result, and they are informed accordingly. */
  248. static BOOLEAN referee_dipc_commit(struct message *message)
  249. {
  250.  struct dipc_list *dl, *dl2, *dl3;
  251.  struct message response;
  252.  int type;
  253.  
  254.  if(verbose)
  255.  {
  256.   sprintf(mstr,"Handling Commit For Key %d of Type %s",
  257.           message->info.key, ipc_type[message->info.type]);
  258.   mess(mstr, INFO);
  259.  }        
  260.  type = message->info.type;             
  261.  response = *message;
  262.  response.address = REFEREE_ADDRESS;
  263.  /* this may be used to inform other tasks of the search result */
  264.  
  265.  response.request = RES_REFEREE;
  266.  /* find the corresponding in the 'wanted' linked list */
  267.  dl = find_in_list(&wanted_first[type], message->info.key);
  268.  while(dl)
  269.  {
  270.   if(SAME_MACHINE(&(dl->address),message->address))
  271.    break;
  272.   dl = get_next_key(dl);
  273.  } 
  274.  if(dl == NULL)
  275.  {
  276.   sprintf(mstr,"ERROR: Commit For Non-Existing Key");
  277.   mess(mstr, INFO);
  278.   return FAIL;
  279.  }
  280.  else
  281.  {
  282.   /* in any case remove the request from wanted list, because either it
  283.      will be thrown away (failer) or put in another linked list (success) */ 
  284.   remove_from_list(&wanted_last[type], dl);        
  285.   if(message->info.arg2 > 0)
  286.   { /* successful COMMIT. put it in existing dipc list */
  287.    if(verbose)
  288.    {
  289.     sprintf(mstr,"Commit: Success");
  290.     mess(mstr, INFO);
  291.    } 
  292.    dl->status = REF_NORMAL;
  293.    dl->mode = message->info.arg3;
  294.    dl->size = message->info.arg2;
  295.     
  296.    add_to_list(&gotten_last[type], dl);         
  297.    /* we should also return FOUND to all the other waiting tasks.
  298.       search from the start and call respond_to */
  299.    dl2 = find_in_list(&wanted_first[type], dl->key);
  300.    while(dl2) 
  301.    {
  302.     dl3 = get_next_key(dl2);
  303.     if(respond_to(dl2) == FAIL)
  304.     {
  305.      sprintf(mstr,"ERROR: Can't Respond To Request");
  306.      mess(mstr, INFO);
  307.     }
  308.     dl2 = dl3;
  309.    }
  310.   }
  311.   else
  312.   {  /* failed commit. remove it and give a chance to another machine */
  313.    if(verbose)
  314.    {
  315.     sprintf(mstr,"Commit: No success");
  316.     mess(mstr, INFO);
  317.    }
  318.    dl2 = get_next_key(dl);
  319.    while(dl2)
  320.    {
  321.     if(SUCCESS == respond_to(dl2))
  322.      break;
  323.     dl2 = get_next_key(dl2); 
  324.    }
  325.    /* destroy the failed request */
  326.    free(dl);   
  327.   }
  328.  }
  329.  /* the process sending the commit is waiting inside its local kernel.
  330.     We have to answer it, so it can continue. */
  331.  response = *message;
  332.  response.address = REFEREE_ADDRESS;
  333.  response.request = RES_REFEREE;
  334.  if(send_in_message(&response, message->address) == FAIL)
  335.  {
  336.   /* don't worry. The worker that sent the commit message will timeout */
  337.   sprintf(mstr,"ERORR: Can't Restart The Commit: %s",
  338.           inet_ntoa(dl2->address.sin_addr));
  339.   mess(mstr, INFO);        
  340.   return FAIL;
  341.  }
  342.  if(verbose)
  343.  {
  344.   sprintf(mstr,"key %d Commit Done",message->info.key);
  345.   mess(mstr, INFO);
  346.  }             
  347.  return SUCCESS;
  348. }
  349.  
  350.  
  351. /* a request to delete a key in referee linked lists. It also checks to see
  352.    if it should inform a shared memory manager process to detach */
  353. static BOOLEAN referee_dipc_delkey(struct message *message)
  354. {
  355.  struct message response;
  356.  struct dipc_list *dl, *dl2;
  357.  int type;
  358.  
  359.  if(verbose)
  360.  {
  361.   sprintf(mstr,"Handling Delete Of Key %d of Type %s",
  362.          message->info.key, ipc_type[message->info.type]);
  363.   mess(mstr, INFO);
  364.  }       
  365.  type = message->info.type;                    
  366.  dl = find_in_list(&gotten_first[type], message->info.key);
  367.  while(dl)
  368.  {
  369.   if(SAME_MACHINE(&(dl->address), message->address))
  370.    break;
  371.   dl = get_next_key(dl);
  372.  } 
  373.  if(dl == NULL)
  374.  {
  375.   sprintf(mstr,"ERROR: There Is No Key To Delete");
  376.   mess(mstr, INFO);
  377.   /* return FAIL; don't return fail, so that the stoped task can resatart */
  378.  } 
  379.  else
  380.  {
  381.   if(verbose)
  382.   {
  383.    if(dl->mode & IPC_OWN)
  384.    {
  385.     sprintf(mstr,"This Is The Owner");
  386.     mess(mstr, INFO);
  387.    }
  388.    else
  389.    {
  390.     sprintf(mstr,"This Isn't The Owner");
  391.     mess(mstr, INFO);
  392.    }  
  393.   }  
  394.   remove_from_list(&gotten_last[type], dl); 
  395.   /* now see if there is only one remaining machine with the key.
  396.      if this is the case and the key type is SHM, send a message 
  397.      to that machine, so that the key_manager can detach itself */
  398.   dl2 = find_in_list(&gotten_first[type], message->info.key);   
  399.   if(type == SHM && dl2 && get_next_key(dl2) == NULL) 
  400.   {
  401.    if(verbose)
  402.    {    
  403.     sprintf(mstr,"Only Machine %s Has This Shared Memory Key",
  404.            inet_ntoa(dl->address.sin_addr));
  405.     mess(mstr, INFO);
  406.    }       
  407.    response = *message;
  408.    response.address = REFEREE_ADDRESS;
  409.    response.request = REQ_SHMMAN;
  410.    response.info.func = DETACH;
  411.    if(send_in_message(&response, dl2->address) == FAIL)
  412.    {
  413.     sprintf(mstr,"ERROR: Can't Inform Shared Memory Owner To Delete");
  414.     mess(mstr, INFO); 
  415.     /* return FAIL; don't return fail, so that the stoped task can resatart */  
  416.    }  
  417.   }
  418.   free(dl); 
  419.  }
  420.  /* in any case, come here and send a reply to original task */
  421.  response = *message;
  422.  response.address = REFEREE_ADDRESS;
  423.  response.request = RES_REFEREE;
  424.  if(send_in_message(&response, message->address) == FAIL)
  425.  {
  426.   sprintf(mstr,"ERORR: Can't Restart The Delete at %s",
  427.                           inet_ntoa(message->address.sin_addr));
  428.   mess(mstr, INFO);
  429.   return FAIL;
  430.  } 
  431.  if(verbose)
  432.  {    
  433.   sprintf(mstr,"key %d Delete Acknowledge Done",message->info.key);   
  434.   mess(mstr, INFO);
  435.  }
  436.  return SUCCESS; 
  437. }
  438.  
  439.  
  440.  
  441. /* a request to remove an IPC structure. This one is comming from the owner
  442.    of the structure. Inform other computers with a structure of the same 
  443.    key */
  444. static BOOLEAN referee_dipc_rmid(struct message *message)
  445. {
  446.  struct message response;
  447.  struct dipc_list *dl, *dl2;
  448.  int type = message->info.type;
  449.  int key = message->info.key;
  450.  
  451.  if(verbose)
  452.  {
  453.   sprintf(mstr,"Handling RMID Of Key %d of Type %s",key, ipc_type[type]); 
  454.   mess(mstr, INFO);
  455.  }
  456.  dl = find_in_list(&gotten_first[type], key);
  457.  while(dl)
  458.  {
  459.   if(SAME_MACHINE(&(dl->address), message->address))
  460.    break;
  461.   dl = get_next_key(dl);
  462.  }
  463.  if(dl == NULL)
  464.  {
  465.   sprintf(mstr,"ERROR: There Is No Key To RMID");
  466.   mess(mstr, INFO);
  467.   /* return FAIL; don't return fail, so that the stoped task can resatart */
  468.  } 
  469.  else
  470.  {  
  471.   response = *message;
  472.   response.address = REFEREE_ADDRESS;
  473.   response.request = REQ_DOWORK;
  474.   /* send all the keys except the first one */ 
  475.   dl2 = find_in_list(&gotten_first[type], key);
  476.   while(dl2)
  477.   {
  478.    if(dl2 != dl) /* not the original one! */
  479.    {
  480.     if(verbose)
  481.     {
  482.      sprintf(mstr,"telling key %d of type %s at %s to RMID",dl2->key, 
  483.               ipc_type[type], inet_ntoa(dl2->address.sin_addr));
  484.      mess(mstr, INFO);
  485.     }                      
  486.     if(send_in_message(&response, dl2->address) == FAIL)
  487.     { 
  488.      sprintf(mstr,"Can't Tell key %d of type %s at %s to RMID",dl2->key, 
  489.                  ipc_type[type], inet_ntoa(dl2->address.sin_addr));
  490.      mess(mstr, INFO);
  491.      /* return FAIL; don't return fail, so that the stoped task can resatart */
  492.     }
  493.    }  
  494.    dl2 = get_next_key(dl2);
  495.   }
  496.   /* now see if there is only one machine with the key. This happens 
  497.     when all the tasks are on the same machine.
  498.     If this is the case and the key type is SHM, send a message 
  499.     to that machine, so that the key_manager can detach itself */
  500.   dl2 = find_in_list(&gotten_first[type], key);  
  501.   if(type == SHM && dl2 && get_next_key(dl2) == NULL)
  502.   {
  503.    if(verbose)
  504.    {    
  505.     sprintf(mstr,"Only Machine %s Has This Shared Memory Key",
  506.             inet_ntoa(dl->address.sin_addr));
  507.     mess(mstr, INFO);
  508.    }
  509.    response = *message;
  510.    response.address = REFEREE_ADDRESS;
  511.    response.request = REQ_SHMMAN;
  512.    response.info.func = DETACH;
  513.    if(send_in_message(&response, dl2->address) == FAIL)
  514.    {
  515.     sprintf(mstr,"ERROR: Can't Inform Shared Memory Owner To Delete");
  516.     mess(mstr, INFO);
  517.     /* return FAIL; don't return fail, so that the stoped task can resatart */  
  518.    } 
  519.   }
  520.  } /* if dl */     
  521.  /*sprintf(mstr,"acknowledging the RMID");
  522.    mess(mstr, INFO); */
  523.  response = *message;
  524.  response.address = REFEREE_ADDRESS;
  525.  response.request = RES_REFEREE;
  526.  if(send_in_message(&response, message->address) == FAIL)
  527.   return FAIL;
  528.  if(verbose)
  529.  {    
  530.   sprintf(mstr,"Key %d RMID Acknowledge Done",key);
  531.   mess(mstr, INFO);
  532.  }
  533.  return SUCCESS; 
  534. }
  535.  
  536.      
  537. static void sig_handler(int signo)
  538. {
  539.  if(verbose)
  540.  {
  541.   sprintf(mstr,"Quiting For Signal No. %d",signo);
  542.   mess(mstr, INFO);
  543.  }
  544.  /* do last works */
  545.  unlink(back_ux_name); /* remove the back_door socket */
  546.  exit(5);
  547. }
  548.  
  549.  
  550. /* checks for stale requests and if timed out, fakes a failed commit.
  551.    This is called at regular intervals */
  552. void check_answers(void)
  553. {
  554.  int type;
  555.  struct message message;
  556.  time_t curr_time;
  557.  struct dipc_list *dl;
  558.  
  559.  if(referee_timeout <= 0 || global_timeout == 0) return;
  560.  
  561.  message.request = RES_REFEREE;
  562.  message.info.arg2 = 0; /* FAIL */
  563.  curr_time = time(NULL);
  564.  for(type = 0; type < 3; type++)
  565.  {
  566.   dl = wanted_first[type].next;
  567.   while(dl)
  568.   {
  569.    if(dl->status == REF_ANSWERED)
  570.    {
  571.     if((curr_time - dl->answer_time) > referee_timeout)
  572.     {
  573.      if(verbose)
  574.      {
  575.       sprintf(mstr,"Handling Stale request at %s",
  576.               inet_ntoa(dl->address.sin_addr));
  577.       mess(mstr, INFO);
  578.      }        
  579.      message.address = dl->address;
  580.      message.info = dl->info;
  581.      message.info.func = COMMIT;
  582.      referee_dipc_commit(&message);
  583.     }
  584.    }
  585.    dl = dl->next;
  586.   }
  587.  }
  588. }
  589.  
  590. /* the back_door control center. It receives request from the UNIX domain 
  591.    socket and executes them. This is for 'out of band' control of the referee,
  592.    without the need to redesign it. The work here should be done quickly, 
  593.    because while the referee is handling back_door requests, it won't be 
  594.    able to handle normal, more important requests. */
  595. static void bd_work_on(int ux_sockfd, struct back_door_message *bd_message)
  596. {
  597.  struct dipc_list *dl;
  598.  struct back_door_message bd_response;
  599.  int type, want_trans, act_trans;
  600.  
  601.  switch(bd_message->cmd)
  602.  {
  603.   case BACK_DOOR_INFO:
  604.    if(verbose)
  605.    { 
  606.     sprintf(mstr,"back door: request for information\n");
  607.     mess(mstr, INFO);
  608.    } 
  609.    /* display the information for shared memories, message queues, and
  610.       semaphore sets */
  611.    for(type = 0; type < 3; type++)
  612.    {
  613.     dl = gotten_first[type].next;
  614.     while(dl)
  615.     {
  616.      bd_response.arg1 = type;
  617.      bd_response.arg2 = dl->key;
  618.      bd_response.arg3 = dl->size;
  619.      bd_response.arg4 = dl->distrib;
  620.      bd_response.arg5 = dl->address.sin_addr.s_addr;
  621.      want_trans = sizeof(bd_response);
  622.      act_trans = writen(ux_sockfd, (char *)&bd_response, want_trans);
  623.      if(act_trans < want_trans)
  624.      {
  625.       sprintf(mstr,"ERROR: sent %d From %d Bytes  BECAUSE %s",
  626.             act_trans, want_trans,strerror(errno));
  627.       mess(mstr, INFO);
  628.       break;        
  629.      }
  630.      dl = dl->next;
  631.     }
  632.     if(dl != NULL) break;
  633.    }
  634.    if(type == 3)
  635.    {
  636.     /* this signals the end of information */ 
  637.     bd_response.arg1 = -1;
  638.     want_trans = sizeof(bd_response);
  639.     act_trans = writen(ux_sockfd, (char *)&bd_response, want_trans);
  640.     if(act_trans < want_trans)
  641.     {
  642.      sprintf(mstr,"ERROR: sent %d From %d Bytes  BECAUSE %s",
  643.            act_trans, want_trans,strerror(errno));
  644.      mess(mstr, INFO);        
  645.     }
  646.    }
  647.    break;
  648.   case BACK_DOOR_REMOVE:
  649.    if(verbose)
  650.    { 
  651.     sprintf(mstr,"back door: request for removal\n");
  652.     mess(mstr, INFO);
  653.    }
  654.    dl = gotten_first[bd_message->arg1].next;
  655.    while(dl)
  656.    {
  657.     if(dl->key == bd_message->arg2 && 
  658.        dl->address.sin_addr.s_addr == bd_message->arg5)
  659.      break;
  660.     dl = dl->next;
  661.    }
  662.    if(dl)
  663.    {
  664.     remove_from_list(&gotten_last[bd_message->arg1], dl);
  665.     if(verbose)
  666.     { 
  667.      sprintf(mstr,"back door: removed the entry\n");
  668.      mess(mstr, INFO);
  669.     }
  670.     /* tell dipcreg of the success */
  671.     bd_message->arg1 = 0;
  672.    }
  673.    else
  674.    {
  675.     if(verbose)
  676.     { 
  677.      sprintf(mstr,"back door: did not find the entry\n");
  678.      mess(mstr, INFO);
  679.     }
  680.     bd_message->arg1 = -1;
  681.    } 
  682.    want_trans = sizeof(*bd_message);
  683.    act_trans = writen(ux_sockfd, (char *)bd_message, want_trans);
  684.    if(act_trans < want_trans)
  685.    {
  686.     sprintf(mstr,"ERROR: Sent %d From %d Bytes  BECAUSE %s",
  687.           act_trans, want_trans,strerror(errno));
  688.     mess(mstr, INFO);        
  689.    }
  690.    break;
  691.    
  692.   default:
  693.    sprintf(mstr,"ERROR: Unknown back door request: %d\n", bd_message->cmd);
  694.    mess(mstr, INFO);
  695.  }
  696. }
  697.     
  698. void referee(void)
  699. {
  700.  fd_set rSelFD; /* for select */
  701.  struct timeval TimeVal;
  702.  int count;
  703.  int want_trans, act_trans;
  704.  struct message message;
  705.  int in_client_len, in_len;
  706.  struct sockaddr_in in_client_addr, in_addr;
  707.  int in_sockfd,in_newsockfd;
  708.  struct sockaddr_un back_ux_addr, back_ux_client_addr;
  709.  int back_ux_len, back_ux_client_len;
  710.  int back_ux_sockfd, back_ux_newsockfd;
  711.  struct sigaction sact;
  712.  struct back_door_message bd_message;
  713.  
  714.  if(verbose)
  715.  { 
  716.   sprintf(mstr,"referee Started");
  717.   mess(mstr, INFO);
  718.  }
  719.  sact.sa_handler = sig_handler;
  720.  sigemptyset(&sact.sa_mask);
  721.  sact.sa_flags = 0;
  722.  
  723.  if(sigaction(SIGINT, &sact, NULL) < 0)
  724.  {
  725.   sprintf(mstr,"ERROR: Can't Catch Signal  BECAUSE %s",strerror(errno));
  726.   mess(mstr, INFO);
  727.  } 
  728.  if(sigaction(SIGTERM, &sact, NULL ) < 0)
  729.  {
  730.   sprintf(mstr,"ERROR: Can't Catch Signal  BECAUSE %s",strerror(errno));
  731.   mess(mstr, INFO);
  732.  } 
  733.  if(sigaction(SIGSEGV, &sact, NULL) < 0)
  734.  {
  735.   sprintf(mstr,"ERROR: Can't Catch Signal  BECAUSE %s",strerror(errno));
  736.  } 
  737.  
  738.  for(count = 0; count < 3; count++)
  739.  {
  740.   gotten_first[count].next = gotten_first[count].prev = NULL;
  741.   gotten_last[count] = &gotten_first[count];
  742.   
  743.   wanted_first[count].next = wanted_first[count].prev = NULL;
  744.   wanted_last[count] = &wanted_first[count];
  745.  } 
  746.  /* prepare the "back door" socket */
  747.  sprintf(back_ux_name,"%s%s",UNIX_PATH,REFEREE_BACKDOOR);
  748.  bzero((char *)&back_ux_addr,sizeof(back_ux_addr));
  749.  back_ux_addr.sun_family = AF_UNIX;
  750.  strcpy(back_ux_addr.sun_path,back_ux_name);
  751.  back_ux_len = strlen(back_ux_addr.sun_path) + sizeof(back_ux_addr.sun_family); 
  752.  
  753.  unlink(back_ux_name);
  754.  back_ux_sockfd = plug(AF_UNIX, (struct sockaddr *)&back_ux_addr, back_ux_len);
  755.  if(back_ux_sockfd < 0)
  756.  { 
  757.   sprintf(mstr,"ERROR: Can't Create Socket %s",back_ux_name);
  758.   mess(mstr, INFO);
  759.   exit(20);
  760.  }
  761.   
  762.  bzero((char *)&in_addr,sizeof(in_addr));
  763.  in_addr.sin_family = AF_INET;
  764.  in_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  765.  in_addr.sin_port = htons(DIPC_REFEREE_PORT);
  766.  in_len = sizeof(in_addr);
  767.   
  768.  in_sockfd = plug(AF_INET, (struct sockaddr *) &in_addr, in_len);
  769.  if(in_sockfd < 0)
  770.  {
  771.   sprintf(mstr,"ERROR: Can't Create Socket");
  772.   mess(mstr, INFO);
  773.   unlink(back_ux_name);
  774.   exit(20);
  775.  }
  776.  
  777.  while(1) 
  778.  {
  779.   TimeVal.tv_sec = referee_timeout;
  780.   TimeVal.tv_usec = 0;
  781.   FD_ZERO(&rSelFD);
  782.   FD_SET(in_sockfd,&rSelFD);
  783.   FD_SET(back_ux_sockfd, &rSelFD);
  784.   if(select(FD_SETSIZE,&rSelFD,NULL,NULL,&TimeVal) < 0)
  785.   {
  786.    sprintf(mstr,"ERROR: select() failed  BECAUSE %s",strerror(errno));
  787.    mess(mstr, INFO);
  788.    close(in_sockfd);
  789.    unlink(back_ux_name);
  790.    exit(20);
  791.   }  
  792.   if(FD_ISSET(in_sockfd,&rSelFD))
  793.   {
  794.    in_client_len = sizeof(in_client_addr);
  795.    if((in_newsockfd = accept(in_sockfd, (struct sockaddr *)&in_client_addr,
  796.                                                       &in_client_len)) < 0)
  797.    {
  798.     sprintf(mstr,"ERROR: accept() Failed  BECAUSE %s",strerror(errno));
  799.     mess(mstr, INFO);
  800.     close(in_sockfd);
  801.     unlink(back_ux_name);
  802.     exit(20);
  803.    }
  804.    want_trans = sizeof(message);
  805.    act_trans = get_in_message(in_newsockfd, &message);
  806.    if(act_trans < want_trans)
  807.    {
  808.     sprintf(mstr,"ERROR: Received %d From %d Bytes  BECAUSE %s",
  809.             act_trans, want_trans,strerror(errno));
  810.     mess(mstr, INFO);        
  811.    }
  812.    else
  813.    {
  814.     if(verbose)
  815.     {
  816.      sprintf(mstr,"Remote Call From %s",inet_ntoa(message.address.sin_addr)); 
  817.      mess(mstr, INFO);
  818.     }
  819.  
  820.     switch(message.info.func)
  821.     {
  822.      case SEARCH:
  823.       referee_dipc_search(&message);
  824.       break;
  825.      case COMMIT:
  826.       referee_dipc_commit(&message); 
  827.       break;
  828.      case DELKEY:
  829.       referee_dipc_delkey(&message);
  830.       break;
  831.      case RMID:
  832.       referee_dipc_rmid(&message);  
  833.       break;
  834.      default: 
  835.       sprintf(mstr,"ERROR: Unknown Request %s",
  836.                                    request_string(message.request)); 
  837.       mess(mstr, INFO);
  838.       break;
  839.     }
  840.    } /* message received */  
  841.    close(in_newsockfd);
  842.   }
  843.   else if(FD_ISSET(back_ux_sockfd,&rSelFD))
  844.   {
  845.    if(verbose)
  846.    {
  847.     sprintf(mstr,"back door call");
  848.     mess(mstr, INFO);
  849.    }  
  850.    back_ux_client_len = sizeof(back_ux_client_addr);
  851.    if((back_ux_newsockfd = accept(back_ux_sockfd, 
  852.          (struct sockaddr *)&back_ux_client_addr, &back_ux_client_len)) < 0)
  853.    {
  854.     sprintf(mstr,"ERROR: accept() Failed  BECAUSE %s",strerror(errno));
  855.     mess(mstr, INFO);
  856.     close(back_ux_newsockfd);
  857.    }
  858.    else
  859.    {
  860.     want_trans = sizeof(bd_message);
  861.     act_trans = readn(back_ux_newsockfd,(char *)&bd_message, want_trans);
  862.     if(act_trans < want_trans)
  863.     {
  864.      sprintf(mstr,"ERROR: Received %d From %d Bytes  BECAUSE %s",
  865.             act_trans, want_trans,strerror(errno));
  866.      mess(mstr, INFO);        
  867.     }
  868.     else
  869.      bd_work_on(back_ux_newsockfd, &bd_message);
  870.     close(back_ux_newsockfd);
  871.    } 
  872.   } /* if back door */ 
  873.   /* either a timeout or a request was serviced, check stale requests */
  874.   check_answers();
  875.  } /* while(1) */
  876. }
  877.